package fxbattle.client.coms;

import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;

import fxbattle.protos.ClientProtos;
import fxbattle.protos.ServerProtos;
import fxbattle.protos.ClientProtos.SetPath;

public class ClientToServerSocket {
	
	private final int fPort;
	private final String fServer;
	private Socket fConnection = null;
	private final BattleMapSocketUpdater fController;
	private final Thread fListenForUpdates = new Thread("Listen For Updates"){
//        int fRunCount = 0;
		@Override
		public void run() {
			while(isConnected()){
				try {
					System.out.println("Available: " + fConnection.getInputStream().available());
					ServerProtos.StateUpdate lNextUpdate = ServerProtos.StateUpdate.parseDelimitedFrom(fConnection.getInputStream());
					fController.updateState(lNextUpdate);
//                    fRunCount ++;
//                    if(fRunCount % 100 == 0){
//                        System.err.println("Run Count is: " + fRunCount);
//                    }
//                    sleep(10);
				} catch (IOException e) {
					fController.failureMessage("Communication Error: " + e.getMessage());
					try {
						fConnection.close();
					} catch (IOException e1) {
						e1.printStackTrace();
					}
					break;
//				} catch (InterruptedException e){
//                    fController.failureMessage("Thread inturrupted.");
//                    break;
                }
			}
		}
	};
	
	public ClientToServerSocket(String iServer, int iPort, BattleMapSocketUpdater iController) {
		fServer = iServer;
		fPort = iPort;
		fController = iController;
	}
	
	public boolean isConnected(){
		return fConnection != null && 
			fConnection.isConnected() && 
			! fConnection.isClosed() && 
			! fConnection.isInputShutdown() && 
			! fConnection.isOutputShutdown();
	}
	
	public ServerProtos.RespondToPlayRequest requestToPlay(String iMyName){
		if(isConnected()){
			throw new IllegalStateException("You're already playing!");
		} else {
			try {
				fConnection = new Socket(fServer, fPort);
			} catch (UnknownHostException e) {
				return makeFailedPlayRequest("Couldn't find host " + fServer);
			} catch (IOException e) {
				return makeFailedPlayRequest("Communications Error", e);
			}
			try {
				ClientProtos.RequestToPlay.newBuilder().setName(iMyName).build().writeDelimitedTo(fConnection.getOutputStream());
				return ServerProtos.RespondToPlayRequest.parseDelimitedFrom(fConnection.getInputStream());
			} catch (IOException e) {
				return makeFailedPlayRequest("Communications Error", e);
			}
		}
	}
	
	public ServerProtos.StateUpdate listenForInitialState(){
		if(fListenForUpdates.isAlive()){
			throw new IllegalStateException("You can't listen for initial state, your already listening for state updates.");
		}
		if(! isConnected() ){
			throw new IllegalStateException("Must be connected in order to get an initial state.");
		}
		try {
			return ServerProtos.StateUpdate.parseDelimitedFrom(fConnection.getInputStream());
		} catch (IOException e) {
			e.printStackTrace();
			try {
				fConnection.close();
			} catch (IOException e1) {
				e1.printStackTrace();
			}
			return null;
		}
	}
	
	public void beginListeningForUpdates(){
		if(fListenForUpdates.isAlive()){
			throw new IllegalStateException("Already listening for Updates.");
		}
		if(! isConnected() ){
			throw new IllegalStateException("Must be connected in order to listen for updates.");
		}
		fListenForUpdates.start();
	}
	
	private static ServerProtos.RespondToPlayRequest makeFailedPlayRequest(String iString, Exception e){
		return makeFailedPlayRequest(iString + ": " + e.getMessage());
	}
	
	private static ServerProtos.RespondToPlayRequest makeFailedPlayRequest(String iString){
		return ServerProtos.RespondToPlayRequest.newBuilder().setReason(iString).build();
	}

	public void requestPathChange(SetPath request) {
		try {
			System.out.println("Sending: " + request);
			request.writeDelimitedTo(fConnection.getOutputStream());
		} catch (IOException e) {
			fController.failureMessage("Couldn't send path change request: " + e.getMessage());
		}
	}
	public static void main(String[] args) {
		System.out.println(System.getProperty("java.class.path"));
	}

}
